15.11 Das Speichern in der Registrierungsdatenbank
 
Manchmal möchte man wichtige oder allgemeine Daten einer Form speichern, um das Fenster beim späteren Öffnen wieder in den Zustand zu versetzen, in dem es vor dem Schließen war. Typischerweise gehören dazu die Größe und die Position des Fensters auf dem Bildschirm. Diese Daten sollten spätestens dann gespeichert werden, wenn das Fenster geschlossen wird.
Prinzipiell eignen sich dazu natürlich Dateien, aber das Betriebssystem Windows bietet mit der Registry eine universelle und allgemeine Datenbank an, in die Informationen geschrieben werden können, die nicht verloren gehen dürfen. Wir wollen uns daher jetzt die Klassen ansehen, die es uns ermöglichen, Daten in die Registrierungsdatenbank zu schreiben und sie später bei Bedarf auszuwerten.
15.11.1 Die Klassen »Registry« und »RegistrKey«
 
Die Registrierungsdatenbank ist hierarchisch aufgebaut und ähnelt strukturell dem Verzeichnissystem. In der Registry werden die Dateninformationen in Keys (Schlüssel) organisiert, die vergleichbar mit einem Verzeichnis sind. Jeder einzelne Schlüssel kann wieder beliebig viele untergeordnete Unterschlüssel verwalten. In den Unterschlüsseln sind die namentlich gekennzeichneten Dateninformationen enthalten.
Maximal sieben Stammschlüssel sind bei einem Windows-Betriebssystem möglich:
|
HKEY_CLASSES_ROOT |
|
HKEY_CURRENT_USER |
|
HKEY_LOCAL_MACHINE |
|
HKEY_USERS |
|
HKEY_PERFORMANCE_DATA |
|
HKEY_CURRENT_CONFIG |
|
HKEY_DYN_DATA |
Anwendungen beschränken sich meist darauf, Einträge im Unterschlüssel Software des Stammschlüssels HKEY_CURRENT_USER vorzunehmen. Wenn Sie diesen Schlüssel in der Registrierungsdatenbank öffnen (geben Sie dazu unter Start · Ausführen... den Dateinamen regedit.exe ein), werden Sie feststellen, dass im Unterschlüssel Software zunächst die Firmennamen eingetragen sind und in den weiteren Unterschlüsseln die Produktnamen.
Die Klasse Registry, die zum Microsoft-spezifischen Namespace Microsoft.Win32 gehört, ermöglicht den Zugriff auf die Stammschlüssel über sieben statische Felder, die schreibgeschützt sind und sich an den Bezeichnern der Stammschlüssel orientieren, beispielsweise:
| public static readonly RegistryKey ClassesRoot;
|
| public static readonly RegistryKey CurrentUser;
|
| public static readonly RegistryKey LocalMachine;
|
Auf die zurückgegebene Referenz vom Typ RegistryKey können Methoden aufgerufen werden, um Unterschlüssel zu erstellen, auf einen Unterschlüssel zuzugreifen oder die in ihm gespeicherten Werte festzulegen oder auszuwerten.
Erstellen eines Unterschlüssels
Zum Erzeugen eines neuen Unterschlüssels dient die Methode CreateSubKey der Klasse RegistryKey, der eine Zeichenfolge übergeben wird, die den Pfad zum Unterschlüssel beschreibt:
| public RegistryKey CreateSubKey(string subKey);
|
CreateSubKey erzeugt nicht nur einen neuen Unterschlüssel, sondern kann auch einen bereits vorhandenen öffnen. Schlägt die Aktion jedoch fehl, ist der Rückgabewert null.
Wir können beispielsweise mit der folgenden Anweisung im Stammschlüssel HKEY_CURRENT_USER im Unterschlüssel Software gleichzeitig auch zwei hierarchisch angeordnete Unterschlüssel erzeugen:
| RegistryKey regKey = Registry.CurrentUser.CreateSubKey(
|
| @"Software\Tollsoft\MeineAnwendung");
|
regKey verweist danach auf den letzten Unterschlüssel, hier also MeineAnwendung, in dem Sie anschließend die Dateninformationen speichern können.
Öffnen eines untergeordneten Schlüssels
Ein existierender Schlüssel wird mit der Methode OpenSubKey auf eine Referenz vom Typ RegistryKey geöffnet:
| public RegistryKey OpenSubKey(string subKey);
|
| public RegistryKey OpenSubKey(string subKey, bool writable);
|
Die erste Variante öffnet einen Schlüssel schreibgeschützt, die zweite erlaubt den schreibenden Zugriff, falls dem booleschen Argument true übergeben wird. Dazu ein Beispiel, um den zuvor erzeugten Unterschlüssel zum Schreiben zu öffnen:
| RegistryKey regKey = Registry.CurrentUser.OpenSubKey(
|
| @"Software\Tollsoft\MeineAnwendung", true);
|
Die Methode gibt null zurück, wenn der Schlüssel nicht existiert. Sie brauchen daher auch keine Ausnahmebehandlung vorzusehen.
Löschen eines Unterschlüssels
Zum Löschen eines untergeordneten Schlüssels bieten sich zwei Methoden an:
| public void DeleteSubKey(string subKey);
|
| public void DeleteSubKey(string subkey, bool throwException)
|
Beiden Methoden wird die Zeichenfolge auf den Unterschlüssel übergeben, den Sie löschen wollen. Es muss sich dabei um einen Unterschlüssel handeln, der selbst keine weiteren Unterschlüssel enthält. Sollte das dennoch der Fall sein, wird eine Ausnahme ausgelöst. Können Sie auf diese Ausnahme verzichten, bietet sich die Überladung an, die einen booleschen Wert entgegennimmt. Ist dieser true, unterscheidet sich das Verhalten nicht von der einparametrigen Methode, wird false übergeben, wird die Ausnahme nicht ausgelöst.
Würde es nur diese Methode geben, wären mehrere Methodenaufrufe notwendig, um eine weiter verzweigte Unterschlüsselstruktur zu löschen. Deshalb wird von der Klasse RegistryKey auch mit DeleteSubKeyTree eine Methode angeboten, die es erlaubt, einen Schlüssel einschließlich aller Unterschlüssel mit einer einzigen Anweisung zu löschen:
| public void DeleteSubKeyTree(string subkey);
|
Schließen der Registrierung
Mit Close der Klasse RegistryKey wird die Registrierung geschlossen. Alle veränderten Dateninhalte werden dabei zurückgeschrieben:
Werte setzen und lesen
Mit den beiden Methoden SetValue und GetValue können Sie auf die Referenz eines RegistryKey-Objekts im aktuellen Unterschlüssel Werte setzen oder gespeicherte Daten auswerten. Sehen wir uns zuerst die Methode zum Speichern einer Dateninformation an, die allerdings voraussetzt, dass der Schlüssel mit Schreibberechtigung geöffnet worden ist:
| public void SetValue(string name, object value);
|
| public void SetValue(string name, object value, RegistryKindValue type);
|
Der erste Parameter erwartet eine Zeichenfolge. Geben Sie hier den Namen des Werts an, der im zweiten Parameter übergeben wird. Vergleichbar ist der Name eines Werts in der Registrierungsdatenbank mit dem Bezeichner einer Variablen. Im zweiten Parameter wird der Wert übergeben. Da dieser vom Typ object ist, werden alle Datentypen akzeptiert, z.B.:
| RegistryKey regKey = Registry.CurrentUser.OpenSubKey(
|
| @"Software\Tollsoft\MeineAnwendung");
|
| regKey.SetValue("x – Position", 0);
|
Neu im .NET Framework 2.0 ist, dass diese Datentypen nun auch unterstützt werden. Grundlage bildet hier die Enumeration RegistryValueKind mit ihren Konstanten.
Tabelle 15.16 Konstanten der Enumeration »RegistryValueKind«
| Member
|
Beschreibung
|
|
Binary
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_BINARY (Binärdaten in beliebiger Form)
|
|
DWord
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_DWORD (32-Bit-Binärzahl).
|
|
ExpandString
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_EXPAND_SZ (Zeichenfolge, die nicht erweiterte Verweise auf Umgebungsvariablen (z.B. %PATH%) enthält).
|
|
MultiString
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_MULTI_SZ (Array von Zeichenfolgen, das auf zwei Nullzeichen (»00«) endet).
|
|
QWord
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_QWORD (64-Bit-Binärzahl).
|
|
String
|
Entspricht dem Win32-API-Registrierungsdatentyp REG_SZ (eine auf 0 (null) endende Zeichenfolge).
|
|
Unknown
|
Gibt einen nicht unterstützten Registrierungsdatentyp an.
|
Die Methode SetValue unterstützt die Typen durch eine Überladung:
Ausgewertet wird ein bestimmter Wert mit der überladenen Methode GetValue:
| public object GetValue(string name);
|
| public object GetValue(string name, object defaultValue);
|
| public object GetValue(string name, object defaultValue RegistryValueKind type);
|
Die einparametrige Methode erwartet nur die Namensangabe des gespeicherten Werts. Wird im aktuellen Schlüssel unter diesem Namen kein Eintrag gefunden, ist der Rückgabewert null. Die zweiparametrige Version reagiert anders, wenn der Name nicht gefunden wird. Sie liefert dann den im zweiten Parameter angegebenen Wert, der als Standardwert interpretiert werden kann. Der letzten Überladung teilen Sie im dritten Parameter mit, von welchem Typ der zu lesende Wert ist. Dazu geben Sie eine der Konstanten der Enumeration RegistryValueKind an.
Sie sollten genau beachten, was Sie SetValue übergeben. Eine Objektreferenz anzugeben wird beim späteren Auswerten scheitern. Denn tatsächlich wird keine Referenz, sondern die Typbeschreibung in die Registrierung geschrieben. Dazu ein Beispiel:
| ClassA obj = new ClassA();
|
| RegistryKey regKey = Registry.CurrentUser.CreateSubKey(
|
| @"Software\Tollsoft\Test");
|
| regKey.SetValue("Referenz auf ClassA", obj);
|
| // Registry schließen
|
| regKey.Close();
|
| regKey = Registry.CurrentUser.OpenSubKey(@"Software\Tollsoft\Test");
|
| MessageBox.Show(regKey.GetValue("Referenz auf ClassA"));
|
Die Rückgabe lautet:
Dabei ist MyNamespace der Namespace, in dem ClassA definiert ist. Wir können daraus folgern, dass die von ToString gelieferte Zeichenfolge gespeichert wird.
Weitere Eigenschaften und Methoden von »RegistryKey«
Die wichtigsten Methoden und Eigenschaften der Klasse RegistryKey habe ich Ihnen auf den letzten Seiten vorgestellt. Damit sind die Möglichkeiten aber noch nicht ausgeschöpft. Beispielsweise werden zwei Eigenschaften zur Verfügung gestellt, die es ermöglichen, die Anzahl der Unterschlüssel oder die Anzahl der in einem Unterschlüssel eingetragenen Werte abzufragen. Insbesondere wenn sich die Anzahl der Einträge dynamisch ändert, sind diese Eigenschaften von Bedeutung.
In der folgenden Tabelle sind alle typspezifischen Eigenschaften und Methoden der Klasse RegistryKey zusammengefasst, um einen guten Überblick zu vermitteln.
Tabelle 15.17 Eigenschaften und Methoden der Klasse »RegistryKey«
| Eigenschaft/Methode
|
Beschreibung
|
| Close
|
(Methode) Schließt den Schlüssel.
|
| CreateSubKey
|
(Methode) Erstellt einen Unterschlüssel oder öffnet einen vorhandenen.
|
| DeleteSubKey
|
(Methode) Löscht den angegebenen Unterschlüssel.
|
| DeleteSubKeyTree
|
(Methode) Löscht den Unterschlüssel einschließlich aller untergeordneten Unterschlüssel.
|
| DeleteValue
|
(Methode) Löscht den angegebenen Wert aus dem Unterschlüssel.
|
| GetSubKeyNames
|
(Methode) Ruft die Namen aller Unterschlüssel ab.
|
| GetValue
|
(Methode) Ruft den angegebenen Wert ab.
|
| GetValueKind
|
(Methode) Liefert den registrierungsspezifischen Typ eines Wertes.
|
| GetValueNames
|
(Methode) Ruft die Namen aller Werte des angegebenen Unterschlüssels ab.
|
| Name
|
(Eigenschaft) Ruft den Namen des Schlüssels ab.
|
| OpenSubKey
|
(Methode) Ruft einen Unterschlüssel ab.
|
| SetValue
|
(Methode) Legt einen Wert fest.
|
| SubKeyCount
|
(Eigenschaft) Ruft die Anzahl der Unterschlüssel ab.
|
| ValueCount
|
(Eigenschaft) Ruft die Anzahl der Werte im Schlüssel ab.
|
 15.11.2 Programmbeispiel zum Speichern in der Registrierung
 
Das Formular des folgenden Beispielprogramms speichert die Positionsdaten Left und Top mit den zuvor beschriebenen Methoden in der Registrierungsdatenbank. Zusätzlich enthält das Formular zwei Eingabetextfelder sowie zwei Kontrollkästchen, deren Inhalt bzw. Einstellungen ebenfalls gespeichert werden. Der im Ereignis FormClosing gespeicherte Zustand wird nach dem erneuten Öffnen des Formulars im Ereignishandler des Load-Ereignisses restauriert.
 Hier klicken, um das Bild zu vergrößern
Abbildung 15.20 Formular des Beispiels »SaveToRegistry«
| // --------------------------------------------------------------
|
| // Beispiel: ...\Kapitel 15\SaveToRegistry
|
| // --------------------------------------------------------------
|
| using Microsoft.Win32;
|
| public partial class Form1 : Form {
|
| string key = @"Software\Tollsoft\MeineAnwendung";
|
| private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
|
| // Positionsinformationen speichern
|
| RegistryKey regKey = Registry.CurrentUser.CreateSubKey(
|
| key + @"\Position");
|
| regKey.SetValue("x – Position", this.Left);
|
| regKey.SetValue("y – Position", this.Top);
|
| // Steuerelementinhalte speichern
|
| regKey = Registry.CurrentUser.CreateSubKey(
|
| key + @"\Position\Controls");
|
| regKey.SetValue("Textbox1", textBox1.Text);
|
| regKey.SetValue("Textbox2", textBox2.Text);
|
| regKey.SetValue("Checkbox1", checkBox1.Checked);
|
| regKey.SetValue("Checkbox2", checkBox2.Checked);
|
| regKey.Close();
|
| }
|
| private void Form1_Load(object sender, EventArgs e) {
|
| RegistryKey regKey = Registry.CurrentUser.OpenSubKey(
|
| key + @"\Position");
|
| // wenn Subkey nicht existiert, Ereignishandler beenden
|
| if(regKey == null)
|
| return;
|
| // Positionsinformationen aus der Registry lesen
|
| this.Left = (int)regKey.GetValue("x – Position", 0);
|
| this.Top = (int)regKey.GetValue("y – Position", 0);
|
| // Inhalt der Steuerelemente restaurieren
|
| regKey = Registry.CurrentUser.OpenSubKey(
|
| key + @"\Position\Controls");
|
| textBox1.Text = (string)regKey.GetValue("Textbox1", "");
|
| textBox2.Text = (string)regKey.GetValue("Textbox2", "");
|
| checkBox1.Checked = Convert.ToBoolean(regKey.GetValue(
|
| "Checkbox1", false));
|
| checkBox2.Checked = Convert.ToBoolean(
|
| regKey.GetValue("Checkbox2", false));
|
| }
|
| }
|
|